package com.security.authority.metadata;

import cn.hutool.core.collection.CollectionUtil;
import com.security.domain.authority.CommonRole;
import com.security.filter.CustomSecurityContext;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.web.util.UrlPathHelper;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;

/**
 * 从数据库加载受保护对象访问需要的权限信息
 * @author 大忽悠
 * @create 2022/10/10 17:15
 */
public abstract class AbstractSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    public static final String SECURITY_METADATA_SOURCE_BEAN_NAME="securityMetadataSource";
    private final UrlPathHelper urlPathHelper=new UrlPathHelper();
    /**
     * 获取当前请求URL的时候,是否保留context-path
     */
    protected Boolean RESERVED_CONTEXT_PATH=Boolean.FALSE;
    /**
     * @param object 实际类型为FilterInvocation
     * @return 受保护对象所需要的权限信息
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        //不需要验证
        if(CustomSecurityContext.noAuth()){
            return null;
        }
        FilterInvocation filterInvocation = (FilterInvocation) object;
        String url = getUrl(filterInvocation);
        List<CommonRole> roleList= loadRoles(url);
        if(CollectionUtil.isEmpty(roleList)){
            return null;
        }
        String[] roles = roleList.stream().map(CommonRole::getAuthority).toArray(String[]::new);
        return SecurityConfig.createList(roles);
    }

    /**
     * 从数据库或者认证中心远程查询得到访问当前url需要具备的角色列表集合
     * @param url
     * @return
     */
    protected abstract List<CommonRole> loadRoles(String url);

    private String getUrl(FilterInvocation object) {
        HttpServletRequest request = object.getRequest();
        return RESERVED_CONTEXT_PATH?request.getRequestURI():urlPathHelper.getPathWithinApplication(request);
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    /**
     * 支持的受保护对象类型是URL
     * @param clazz
     * @return
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}
